package org.examples.java.lang;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

public class ExceptionsTest {

    @Test(expected = ArithmeticException.class)
    public void testArithmeticException() {
        new ArithmeticException();
        new ArithmeticException("");
        @SuppressWarnings("unused")
        int i = 5 / 0;
    }

    @Test(expected = ArrayIndexOutOfBoundsException.class)
    public void testArrayIndexOutOfBoundsException() {
        new ArrayIndexOutOfBoundsException();
        new ArrayIndexOutOfBoundsException("");
        new ArrayIndexOutOfBoundsException(1);

        int[] array = { 1, 2 };
        array[0] = array[3];
    }

    @Test(expected = ArrayStoreException.class)
    public void testArrayStoreException() {
        new ArrayStoreException();
        new ArrayStoreException("");

        Object[] integers = new Integer[] { 1, 2 };
        Object[] strings = { "1", "2" };

        assertTrue(strings instanceof Object[]);
        integers[0] = strings[0];
    }

    @Test(expected = ClassCastException.class)
    public void testClassCastException() {
        new ClassCastException();
        new ClassCastException("");

        Object integer = 1;
        @SuppressWarnings("unused")
        String string = (String) integer;
    }

    // Thrown to indicate that the clone method in class Object has been called to clone an object, but that the
    // object's class does not implement the Cloneable interface.
    @Test(expected = CloneNotSupportedException.class)
    public void testCloneNotSupportedException() throws CloneNotSupportedException {
        new CloneNotSupportedException();
        new CloneNotSupportedException("");

        new Object() {
            private void redirectClone() throws CloneNotSupportedException {
                clone();
            }
        }.redirectClone();
    }

    enum Alphabet {
        A, B, C
    };

    // Thrown when an application tries to access an enum constant by name and the enum type contains no constant with
    // the specified name.
    @Test(expected = EnumConstantNotPresentException.class)
    public void testEnumConstantNotPresentException() {
        EnumConstantNotPresentException exception = new EnumConstantNotPresentException(Alphabet.class, "");
        assertEquals(Alphabet.class, exception.enumType());
        assertEquals("", exception.constantName());

        // didn't find a way to cause to be thrown
        throw exception;
    }

    // The class Exception and its subclasses are a form of Throwable that indicates conditions that a reasonable
    // application might want to catch.
    @Test(expected = Exception.class)
    public void testException() throws Exception {
        new Exception();
        new Exception("");

        throw new Exception();
    }

    // An IllegalAccessException is thrown when an application tries to reflectively create an instance (other than an
    // array), set or get a field, or invoke a method, but the currently executing method does not have access to the
    // definition of the specified class, field, method or constructor.
    // @Test(expected = IllegalAccessException.class)
    public void testIllegalAccessException() {
        new IllegalAccessException();
        new IllegalAccessException("");

    }

    // Thrown to indicate that a method has been passed an illegal or inappropriate argument.
    @Test(expected = IllegalArgumentException.class)
    public void testIllegalArgumentException() {
        new IllegalArgumentException();
        new IllegalArgumentException("");

        Alphabet.valueOf("XXX");
    }

    // Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting
    // on an object's monitor without owning the specified monitor.
    // @Test(expected = IllegalMonitorStateException.class)
    public void testIllegalMonitorStateException() {
        new IllegalMonitorStateException();
        new IllegalMonitorStateException("");
    }

    // Signals that a method has been invoked at an illegal or inappropriate time.
    // @Test(expected = IllegalStateException.class)
    public void testIllegalStateException() {
        new IllegalStateException();
        new IllegalStateException("");
    }

    // Thrown to indicate that a thread is not in an appropriate state for the requested operation.
    // @Test(expected = IllegalThreadStateException.class)
    public void testIllegalThreadStateException() {
        new IllegalThreadStateException();
        new IllegalThreadStateException("");
    }

    // Thrown to indicate that an index of some sort (such as to an array, to a string, or to a vector) is out of range.
    // @Test(expected = IndexOutOfBoundsException.class)
    public void testIndexOutOfBoundsException() {
        new IndexOutOfBoundsException();
        new IndexOutOfBoundsException("");
    }

    // Thrown when an application tries to create an instance of a class using the newInstance method in class Class,
    // but the specified class object cannot be instantiated.
    @Test(expected = InstantiationException.class)
    public void testInstantiationException() throws InstantiationException, IllegalAccessException {
        new InstantiationException();
        new InstantiationException("");

        Number.class.newInstance();
    }

    // Thrown when a thread is waiting, sleeping, or otherwise occupied, and the thread is interrupted, either before or
    // during the activity.
    // @Test(expected = InterruptedException.class)
    public void testInterruptedException() {
        new InterruptedException();
        new InterruptedException("");
    }

    // Thrown if an application tries to create an array with negative size.
    // @Test(expected = NegativeArraySizeException.class)
    public void testNegativeArraySizeException() {
        new NegativeArraySizeException();
        new NegativeArraySizeException("");
    }

    // Signals that the class doesn't have a field of a specified name.
    // @Test(expected = NoSuchFieldException.class)
    public void testNoSuchFieldException() {
        new NoSuchFieldException();
        new NoSuchFieldException("");
    }

    // Thrown when a particular method cannot be found.
    // @Test(expected = NoSuchMethodException.class)
    public void testNoSuchMethodException() {
        new NoSuchMethodException();
        new NoSuchMethodException("");
    }

    // Thrown when an application attempts to use null in a case where an object is required.
    // @Test(expected = NullPointerException.class)
    public void testNullPointerException() {
        new NullPointerException();
        new NullPointerException("");
    }

    // Thrown to indicate that the application has attempted to convert a string to one of the numeric types, but that
    // the string does not have the appropriate format.
    // @Test(expected = NumberFormatException.class)
    public void testNumberFormatException() {
        new NumberFormatException();
        new NumberFormatException("");
    }

    // RuntimeException is the superclass of those exceptions that can be thrown during the normal operation of the Java
    // Virtual Machine.
    // @Test(expected = RuntimeException.class)
    public void testRuntimeException() {
        new RuntimeException();
        new RuntimeException("");
    }

    // Thrown by the security manager to indicate a security violation.
    // @Test(expected = SecurityException.class)
    public void testSecurityException() {
        new SecurityException();
        new SecurityException("");
    }

    // Thrown by String methods to indicate that an index is either negative or greater than the size of the string.
    // @Test(expected = StringIndexOutOfBoundsException.class)
    public void testStringIndexOutOfBoundsException() {
        new StringIndexOutOfBoundsException();
        new StringIndexOutOfBoundsException("");
    }

    // Thrown when an application tries to access a type using a string representing the type's name, but no definition
    // for the type with the specified name can be found.
    // @Test(expected = TypeNotPresentException.class)
    public void testTypeNotPresentException() {
        new TypeNotPresentException("", null);
    }

    // Thrown to indicate that the requested operation is not supported.
    // @Test(expected = UnsupportedOperationException.class)
    public void testUnsupportedOperationException() {
        new UnsupportedOperationException();
        new UnsupportedOperationException("");
    }

}
